package net.xxcxcxcx.xc_enhancedmob.render.boss_bar.complete.sever;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.xxcxcxcx.xc_enhancedmob.packet.CustomNbtPacket;
import net.xxcxcxcx.xc_enhancedmob.render.boss_bar.column.sever.SeverCustomBossBarColumn;
import net.xxcxcxcx.xc_enhancedmob.render.boss_bar.complete.BaseCustomBossBarComplete;
import org.jetbrains.annotations.Nullable;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * 负责处理发送数据包的问题。
 * <p>Players里面是所有可以渲染这个实体的玩家的集合。
 * <p>RenderPlayers里面是所有需要渲染这个boss血条的玩家的集合。
 */
public class SeverCustomBossBarComplete extends BaseCustomBossBarComplete implements SeverBaseCustomBossBarComplete {
    private final Set<ServerPlayerEntity> Players = Sets.newHashSet();//所有可以加载BossBar的玩家实体，用于维护更新集合
    private final Set<ServerPlayerEntity> RenderPlayers = Sets.newHashSet();//所有符合加载条件的玩家实体，用于加载玩家集合
    private final Set<ServerPlayerEntity> UnmodifiablePlayers = Collections.unmodifiableSet(this.Players);//玩家的不可修改集合
    private final Set<ServerPlayerEntity> UnmodifiableRenderPlayers = Collections.unmodifiableSet(this.RenderPlayers);//加载玩家的不可修改集合
    double VisibleRange = 128;//渲染距离
    private Boolean visible = false;//是否可见
    @Nullable
    private MobEntity mobEntity = null;

    public SeverCustomBossBarComplete(MobEntity mobEntity) {
        this(mobEntity, null, false);
    }

    public SeverCustomBossBarComplete(NbtCompound nbtCompound) {
        readCustomDataFromNbt(nbtCompound);
    }

    public SeverCustomBossBarComplete(MobEntity mobEntity, Text customName) {
        this(mobEntity, customName, false);
    }

    public SeverCustomBossBarComplete(MobEntity mobEntity, Text customName, boolean b) {
        this(mobEntity, customName, b, 0);
    }

    public SeverCustomBossBarComplete(MobEntity mobEntity, Text customName, boolean b, int sortcount) {
        this.mobEntity = mobEntity;
        setName(customName);
        setShowname(b);
        setSortCount(sortcount);
        getName().setDirty(false);
        getShowname().setDirty(false);
        getSortCount().setDirty(false);
    }

    //添加玩家
    @Override
    public void addPlayer(ServerPlayerEntity player) {
        this.Players.add(player);
        UpdataRader();
    }

    //移除玩家
    @Override
    public void removePlayer(ServerPlayerEntity player) {
        this.Players.remove(player);
        UpdataRader();
    }

    //添加加载玩家
    @Override
    public void addRenderPlayer(ServerPlayerEntity player) {
        this.RenderPlayers.add(player);
        Updata(UpdataType.ALL, player);
    }

    //移除加载玩家
    @Override
    public void removeRenderPlayer(ServerPlayerEntity player) {
        this.RenderPlayers.remove(player);
        Updata(UpdataType.REMOVE, player);
    }

    //清除所有玩家
    @Override
    public void clearPlayers() {
        if (!this.Players.isEmpty()) {
            for (ServerPlayerEntity serverPlayerEntity : Lists.newArrayList(this.Players)) {
                this.removePlayer(serverPlayerEntity);
            }
        }
        if (!this.RenderPlayers.isEmpty()) {
            for (ServerPlayerEntity serverPlayerEntity : Lists.newArrayList(this.RenderPlayers)) {
                this.removeRenderPlayer(serverPlayerEntity);
            }
        }
    }


    //更新玩家加载信息
    @Override
    public void UpdataRader() {
        Set<ServerPlayerEntity> needRenderplayer = new HashSet<>(Players);
        for (ServerPlayerEntity serverPlayer : Players) {
            if (mobEntity.getPos().distanceTo(serverPlayer.getPos()) > VisibleRange) {
                needRenderplayer.remove(serverPlayer);
            }
        }
        Set<ServerPlayerEntity> unneedRenderplayer = new HashSet<>(RenderPlayers);
        unneedRenderplayer.removeAll(needRenderplayer);
        unneedRenderplayer.forEach(this::removeRenderPlayer);
        needRenderplayer.removeAll(RenderPlayers);
        needRenderplayer.forEach(this::addRenderPlayer);
    }

    //发送网络包更新血条信息
    @Override
    public void Updata(UpdataType updataType, ServerPlayerEntity player) {
        if (getMobEntity() != null) {
            switch (updataType) {
                case ALL -> {
                    NbtCompound nbtCompound = new NbtCompound();
                    writeCustomDataToNbt(nbtCompound);
                    nbtCompound.putString("kind", UpdataType.ALL.toString());
                    NbtCompound nbt = new NbtCompound();
                    nbt.put("Bossbar", nbtCompound);
                    player.networkHandler.sendPacket(CustomNbtPacket.creat(getMobEntity().getEntityId(), nbt));
                }
                case REMOVE -> {
                    NbtCompound nbtCompound = new NbtCompound();
                    nbtCompound.putString("kind", UpdataType.REMOVE.toString());
                    NbtCompound nbt = new NbtCompound();
                    nbt.put("Bossbar", nbtCompound);
                    player.networkHandler.sendPacket(CustomNbtPacket.creat(getMobEntity().getEntityId(), nbt));
                }
            }
        }
    }

    //tick循环确定哪些玩家可以加载实体
    @Override
    public void tick(MobEntity mobEntity) {
        super.tick(mobEntity);
        if (this.getMobEntity() == null) {
            this.setMobEntity(mobEntity);
        }
        if (mobEntity.world.getTime() % 20 == 0 && getVisible()) {
            UpdataRader();
        }
        if (getDrity()) {//更新bossbar数据
            setDrity(false);
            NbtCompound nbtCompound = new NbtCompound();
            writeDrityCustomDataToNbt(nbtCompound);
            nbtCompound.putString("kind", UpdataType.UPDATA.toString());
            NbtCompound nbt = new NbtCompound();
            nbt.put("Bossbar", nbtCompound);
            RenderPlayers.forEach(player -> player.networkHandler.sendPacket(CustomNbtPacket.creat(getMobEntity().getEntityId(), nbt)));
        }
    }

    @Override
    public Set<ServerPlayerEntity> getUnmodifiablePlayers() {
        return UnmodifiablePlayers;
    }

    @Override
    public Set<ServerPlayerEntity> getUnmodifiableRenderPlayers() {
        return UnmodifiableRenderPlayers;
    }

    @Override
    public Boolean getVisible() {
        return visible;
    }

    @Override
    public void setVisible(Boolean visible) {
        this.visible = visible;
    }

    @Override
    public void readCustomDataFromNbt(NbtCompound nbt) {
        for (String s : nbt.getKeys()) {
            if (s.equals("name")) {
                setName(Text.Serializer.fromJson(nbt.getString("name")));
                continue;
            }
            if (s.equals("visible")) {
                setVisible(nbt.getBoolean("visible"));
                continue;
            }
            if (s.equals("showname")) {
                setShowname(nbt.getBoolean("showname"));
                continue;
            }
            if (s.equals("SortCount")) {
                setSortCount(nbt.getInt("SortCount"));
                continue;
            }
            getBossColumn().add(new SeverCustomBossBarColumn(nbt.getCompound(s)));
        }
    }

    @Override
    public void writeCustomDataToNbt(NbtCompound nbt) {
        super.writeCustomDataToNbt(nbt);
        nbt.putBoolean("visible", getVisible());
    }

    public MobEntity getMobEntity() {
        return mobEntity;
    }

    public void setMobEntity(MobEntity mobEntity) {
        this.mobEntity = mobEntity;
    }

    public enum UpdataType {
        ALL, UPDATA, REMOVE
    }
}
